/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MC_CAMERA_TRACKING_CONTROLLER_H
#define MC_CAMERA_TRACKING_CONTROLLER_H
#include <map>
#include "mechbody_controller_ipc_interface_code.h"
#include "mechbody_controller_log.h"
#include "mechbody_controller_types.h"
#include "mc_motion_manager.h"
#include "camera_manager.h"
#include "mech_session.h"
#include "istream_metadata.h"
#include "sensor_agent.h"
#include "sensor_agent_type.h"

namespace OHOS {
namespace MechBodyController {

struct AppSetting {
    bool isTrackingEnabled = true;
    CameraTrackingLayout cameraTrackingLayout = CameraTrackingLayout::DEFAULT;
};

struct CameraInfo{
    int32_t targetId;
    float sensorWidth = 36.0f; // All devices have sensor width equivalent to 36mm
    float sensorHeight = 24.0f; // All devices have sensor height equivalent to 24mm
    uint8_t fovV = 0;
    uint8_t fovH = 0;
    int32_t width = 0;
    int32_t height = 0;
    float zoomFactor = 0;
    bool isRecording = false;
    bool currentTrackingEnable = true;
    CameraTrackingLayout currentCameraTrackingLayout = CameraTrackingLayout::DEFAULT;
    CameraType cameraType = CameraType::BACK;

    std::string ToString() {
        return "targetId: " + std::to_string(targetId) +
               ", sensorWidth: " + std::to_string(sensorWidth) +
               ", sensorHeight: " + std::to_string(sensorHeight) +
               ", fovV: " + std::to_string(fovV) +
               ", fovH: " + std::to_string(fovH) +
               ", width: " + std::to_string(width) +
               ", height: " + std::to_string(height) +
               ", zoomFactor: " + std::to_string(zoomFactor) +
               ", isRecording: " + std::to_string(isRecording) +
               ", currentTrackingEnable: " + std::to_string(currentTrackingEnable) +
               ", currentCameraTrackingLayout: " + std::to_string(static_cast<int32_t>(currentCameraTrackingLayout)) +
               ", cameraType: " + std::to_string(static_cast<uint8_t>(cameraType));
    }


};

enum class TrackingObjectType : uint8_t {
    MSG_OBJ_OTHER = 0,
    MSG_OBJ_HEAD_SHOULDER = 1,
    MSG_OBJ_PERSON = 2,
    MSG_OBJ_CAR = 3,
    MSG_OBJ_BOAT = 4,
    MSG_OBJ_FACE = 5,
    MSG_OBJ_HUMAN_BODY = 6,
    MSG_OBJ_HUMAN_HEAD = 7,
    MSG_OBJ_ANIMAL_BODY = 8,
    MSG_OBJ_ANIMAL_HEAD = 9,
};

class MechSessionCallbackImpl : public CameraStandard::MechSessionCallback {
public:
    ~MechSessionCallbackImpl() override = default;

    void OnFocusTrackingInfo(CameraStandard::FocusTrackingMetaInfo info) override;

    void OnCameraAppInfo(const std::vector<CameraStandard::CameraAppInfo> &cameraAppInfos) override;
};

class McCameraTrackingController{
public:
    static McCameraTrackingController& GetInstance();
private:
    McCameraTrackingController(const McCameraTrackingController&) = delete;
    McCameraTrackingController& operator= (const McCameraTrackingController&) = delete;
    McCameraTrackingController(McCameraTrackingController&&) = delete;
    McCameraTrackingController& operator= (McCameraTrackingController&&) = delete;

public:
    McCameraTrackingController();
    ~McCameraTrackingController();
    void Init();
    void UnInit();
    int32_t OnUsingAppChange(const CameraStandard::CameraAppInfo &cameraAppInfo);
    int32_t OnFocusTracking(CameraStandard::FocusTrackingMetaInfo &info);
    int32_t SetTrackingEnabled(const uint32_t &tokenId, bool &isEnabled);
    int32_t GetTrackingEnabled(const uint32_t &tokenId, bool &isEnabled);
    int32_t RegisterTrackingEventCallback(const uint32_t &tokenId, sptr<IRemoteObject> callback);
    int32_t UnRegisterTrackingEventCallback(const uint32_t &tokenId);
    int32_t OnTrackingEvent(const int32_t &mechId, const TrackingEvent &event);
    int32_t SetTrackingLayout(CameraTrackingLayout &cameraTrackingLayout);
    int32_t SetTrackingLayout(const uint32_t &tokenId, CameraTrackingLayout &cameraTrackingLayout);
    int32_t GetTrackingLayout(const uint32_t &tokenId, CameraTrackingLayout &cameraTrackingLayout);
    std::shared_ptr<CameraInfo> GetCurrentCameraInfo() const;

private:
    std::shared_ptr<CameraInfo> CalculateCameraInfo(const CameraStandard::CameraAppInfo &cameraAppInfo);
    int32_t UpdateMotionManagers(uint32_t tokenId);
    std::shared_ptr<TrackingFrameParams> BuildTrackingParams(CameraStandard::FocusTrackingMetaInfo &info);
    int32_t UpdateMotionsWithTrackingData(
        const std::shared_ptr<TrackingFrameParams> &params, int32_t trackingObjectId);

    int32_t ParseRectToROI(CameraStandard::Rect &rect, ROI &roi);
    void AddROIToWindow(CameraStandard::Rect &rect);
    bool IsSelectTrackingObject();
    int32_t SelectTrackingTarget(std::vector<sptr<CameraStandard::MetadataObject>> &targets,
        sptr<CameraStandard::MetadataObject> &finalTarget, CameraStandard::Rect trachingRegion);
    double ComputeRegistration(sptr<CameraStandard::MetadataObject> &target, CameraStandard::Rect &trackingRegion);
    bool FilterDetectedObject(sptr<CameraStandard::MetadataObject> &detectedObject);
    void UpdateROI(std::shared_ptr<TrackingFrameParams> &trackingFrameParams, CameraStandard::Rect &rect);
    static void SensorCallback(SensorEvent* event);
    static MobileRotation CalculateSensorRotation(GravityData* gravityData);
    void ConvertObjectType(CameraStandard::MetadataObjectType &cameraObjectType, uint8_t &mechObjectType);
    void RegisterTrackingListener();
    void UnRegisterTrackingListener();
    void RegisterSensorListener();
    void UnRegisterSensorListener();
    float ParseLayout(CameraTrackingLayout &cameraTrackingLayout);
    float ParseReverseLayout(CameraTrackingLayout &cameraTrackingLayout);

public:
    std::mutex trackingEventCallbackMutex_;
    std::map<uint32_t, sptr<IRemoteObject>> trackingEventCallback_;
    CameraStandard::CameraAppInfo cameraAppInfo_;

private:
    std::mutex cameraTrackingControllerInitMutex_;
    std::mutex appSettingsMutex_;
    std::map<uint32_t, std::shared_ptr<AppSetting>> appSettings;

    SensorUser user = { "", nullptr, nullptr };
    MobileRotation sensorRotation_ = MobileRotation::UP;
    sptr<CameraStandard::MechSession> pMechSession;
    std::shared_ptr<CameraInfo> currentCameraInfo_ = std::make_shared<CameraInfo>();

    std::mutex roiWindowMutex_;
    std::deque<ROI> roiWindow_;
    std::shared_ptr<TrackingFrameParams> lastTrackingFrame_ = std::make_shared<TrackingFrameParams>();
};
} // namespace MechBodyController
} // namespace OHOS
#endif // MC_CAMERA_TRACKING_CONTROLLER_H